//-----------------------------------------------------------------------
// <copyright file="ACTPerfTest.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY 
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
// PARTICULAR PURPOSE.
// </copyright>
// <author>Richard Florance</author>
// <email>richfl</email>
// <date>2004-09-29</date>
// <summary>Build Task to run an ACT Performance test.</summary>
//-----------------------------------------------------------------------

namespace Microsoft.Sdc.Tasks
{
    using System;
    using System.Reflection;
    using System.Collections;
    using System.Runtime.InteropServices;
    using Microsoft.Sdc.Tasks;
    using Microsoft.Build.Framework;

    /// <summary>
    /// This class implements a generic way of running any ACT test script as part of a build task.
    /// </summary>
    public class ACTPerfTest : TaskBase
    {
        string projectPath;
        string projectName;
        string testName;
        int duration;
        int noOfThreads;
//        double failTime;
        string ResultsXml;


        public ACTPerfTest()
        {
            duration = 30;  //default test duration - 30 seconds
            noOfThreads = 5; // default concurrency - 5 users
        }

        protected override void InternalExecute()
        {
            ComWrapper currentTest;
            ComWrapper tests;
            ComWrapper testProperties;
            ComWrapper testProperty;
            ComWrapper reports;
            ComWrapper testResults;
            ComWrapper actProject = GetActProject(ProjectPath, ProjectName);
            ComWrapper actController = GetActController();

            try
            {
                tests = new ComWrapper (actProject.GetProperty( "Tests"));
                currentTest = new ComWrapper(tests.GetProperty("Item", TestName));
                testProperties = new ComWrapper(currentTest.GetProperty("Properties"));
                testProperty = new ComWrapper(testProperties.GetProperty("Item", "TestProperties:Duration"));
                testProperty.SetProperty("Value", new Object[]{Duration});
                testProperty = new ComWrapper(testProperties.GetProperty("Item", "DynamicTest:NumberOfThreads"));
                testProperty.SetProperty("Value", new Object[] {NoOfUsers});
                actController.CallMethod("StartTest", new object [] {actProject.ComObject, currentTest.ComObject, true});
            }
            catch (Exception ex) // report any exceptions thrown by ACT as a test failure.
            {
                throw new TaskException("Perf.TestFailed", ex.Message);
            }
            reports = new ComWrapper(currentTest.GetProperty("Reports"));
            testResults = new ComWrapper(reports.GetProperty("Item", (int)reports.GetProperty("Count")));
            ResultsXml = ProjectPath;
            if (!ProjectPath.EndsWith("\\"))
            {
                ResultsXml += "\\";
            }

            //
            // verify test ran for full duration. if not flag test as having failed.
            //
            ResultsXml += (string)testResults.GetProperty("Name") + ".xml";
            if (Convert.ToInt32(testResults.GetProperty("Duration")) < Duration)
            {
                throw new TaskException("Perf.TestAborted");
            }

            //
            // determine if any results returned a 400 or 500 class http error. if so flag the test as having failed.
            //
            ComWrapper requests = new ComWrapper(testResults.GetProperty("Requests"));
            int reqCount = Convert.ToInt32(requests.GetProperty("Count"));
            for  (int i = 1 ; i <= reqCount; i++)  //each (ComWrapper request in (ComWrapper)testResults.CallMethod("Requests"))
            {
                ComWrapper request = new ComWrapper(requests.GetProperty("Item", i));
                ComWrapper responseCodes = new ComWrapper(request.GetProperty("ResponseCodes"));
                int respCount = Convert.ToInt32(responseCodes.GetProperty("Count"));
                for (int j = 1; j <= respCount; j++) //each (ComWrapper responseCode in request.CallMethod("ResponseCodes"))
                {
                    ComWrapper responseCode = new ComWrapper(responseCodes.GetProperty("Item", j));
                    if (Convert.ToInt32(responseCode.GetProperty("Type")) >= 400)
                    {
                        throw new TaskException("Perf.RequestFailed", (string)request.GetProperty("Path"), (string)responseCode.GetProperty("Type"));
                    }
                }
                //
                // following code should check that all requests (on average) completed within the maximum request time.
                // having problems getting "get_DataValue" to work and don't have time to fix it now.
                //
//                ComWrapper dataValue = new ComWrapper(request.CallMethod("get_DataValue", new object[] { "TTLB", "AVG" }));
//                double requestTTLB = Convert.ToDouble(dataValue.GetProperty("Value"));
//                if (requestTTLB > failTime)
//                {
//                    throw new TaskException("Perf.TestTooSlow", (string)request.GetProperty("Path"), requestTTLB.ToString());
//                }
            }
        }

        internal ComWrapper GetActController()
        {
            ComWrapper actController = new ComWrapper("ACT.Controller");
            return actController;
        }

        internal ComWrapper GetActProject(string ProjectPath, string ProjectName)
        {
            ComWrapper actProject = new ComWrapper("ACT.Project");
            actProject.CallMethod("Open", new object[] { ProjectPath, ProjectName, false });
            return actProject;
        }

        [Required]
        public string ProjectPath // path to ACT project file
        {
            get { return projectPath; }
            set { projectPath = value; }
        }

        [Required]
        public string ProjectName // name of act project to load
        {
            get { return projectName; }
            set { projectName = value; }
        }

        [Required]
        public string TestName // name of test within project to execute
        {
            get { return testName; }
            set { testName = value; }
        }

        public int Duration // duration of test
        {
            get { return duration; }
            set { duration = value; }
        }

        public int NoOfUsers // no of concurrent users
        {
            get { return noOfThreads; }
            set { noOfThreads = value; }
        }

//        public int FailTime
//        {
//            get { return Convert.ToInt32(failTime * 1000); }
//            set { failTime = Convert.ToDouble(value) / 1000; }
//        }

        [Output]
        public string GetResultsXml //returns path to results XML file for this test run
        {
            get { return ResultsXml; }
        }
    }
}